/*
 * Copyright 2008-2013 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.fsquare.component.module.payment;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.broadleafcommerce.common.money.Money;
import org.broadleafcommerce.common.time.SystemTime;
import org.broadleafcommerce.common.web.BroadleafLocaleResolver;
import org.broadleafcommerce.core.payment.domain.CreditCardPaymentInfo;
import org.broadleafcommerce.core.payment.domain.PaymentResponseItem;
import org.broadleafcommerce.core.payment.service.PaymentContext;
import org.broadleafcommerce.core.payment.service.exception.PaymentException;
import org.broadleafcommerce.core.payment.service.module.DefaultModule;
import org.broadleafcommerce.core.payment.service.type.PaymentInfoAdditionalFieldType;
import org.broadleafcommerce.core.payment.service.type.PaymentInfoType;
import org.joda.time.DateTime;

import com.fsquare.service.paypal.PayPalService;
import com.paypal.api.payments.Amount;
import com.paypal.api.payments.CreditCard;
import com.paypal.api.payments.Payment;
import com.paypal.api.payments.RelatedResources;
import com.paypal.api.payments.Transaction;


public class PayPalCreditCardPaymentModule extends DefaultModule {

	private static final Log LOG = LogFactory.getLog(PayPalCreditCardPaymentModule.class);

    @Resource(name = "blLocaleResolver")
    protected BroadleafLocaleResolver localeResolver;
    
    @Resource(name = "payPalService")
    protected PayPalService payPalService;
    
    
    @Override
    public PaymentResponseItem processAuthorize(PaymentContext paymentContext, Money amountToAuthorize, PaymentResponseItem responseItem) throws PaymentException {
    	System.out.println("**** processAuthorize ****\n");
    	throw new PaymentException("Problem processing Credit Card.");
    }

    @Override
    public PaymentResponseItem processReverseAuthorize(PaymentContext paymentContext, Money amountToReverseAuthorize, PaymentResponseItem responseItem) throws PaymentException {
    	System.out.println("**** processReverseAuthorize ****\n");
    	throw new PaymentException("reverse authorize not implemented.");
    }

    @Override
    public PaymentResponseItem processAuthorizeAndDebit(PaymentContext paymentContext, Money amountToReverseAuthorize, PaymentResponseItem responseItem) throws PaymentException {
    	System.out.println("**** processAuthorizeAndDebit ****\n");
    	try{
	        return debit(paymentContext);

    	}catch(Exception e){
    		e.printStackTrace();
    		throw new PaymentException("Problem processing Credit Card.");
    	}

    }

    @Override
    public PaymentResponseItem processDebit(PaymentContext paymentContext, Money amountToReverseAuthorize, PaymentResponseItem responseItem) throws PaymentException {
    	System.out.println("**** processDebit ****\n");       

    	try{
    		Map<String, Object> result = payPalService.creditCardPayment(paymentContext);
    		responseItem = buildBasicResponse(result, responseItem, paymentContext);
	        LOG.info(result.get(PayPalService.RESULT_PAYMENT));
	        LOG.info(responseItem);
	        responseItem.setTransactionSuccess(true);
	        return responseItem;

    	}catch(Exception e){
    		e.printStackTrace();
    		throw new PaymentException("Problem processing Credit Card.");
    	}

    }

    @Override
    public PaymentResponseItem processCredit(PaymentContext paymentContext, Money amountToReverseAuthorize, PaymentResponseItem responseItem) throws PaymentException {
    	System.out.println("**** processCredit ****\n"); 
    	throw new PaymentException("credit not implemented.");
    }

    @Override
    public PaymentResponseItem processVoidPayment(PaymentContext paymentContext, Money amountToReverseAuthorize, PaymentResponseItem responseItem) throws PaymentException {
    	System.out.println("**** processVoidPayment ****\n");
    	throw new PaymentException("voidPayment not implemented.");
    }

    @Override
    public PaymentResponseItem processBalance(PaymentContext paymentContext, PaymentResponseItem responseItem) throws PaymentException {
    	System.out.println("**** processBalance ****\n");
    	throw new PaymentException("balance not implemented.");
    }

    @Override
    public PaymentResponseItem processPartialPayment(PaymentContext paymentContext, Money amountToDebit, PaymentResponseItem responseItem) throws PaymentException {
    	System.out.println("**** processPartialPayment ****\n");
    	throw new PaymentException("partial payment not implemented.");
    }

    @Override
    public Boolean isValidCandidate(PaymentInfoType paymentType) {
    	return PaymentInfoType.CREDIT_CARD.equals(paymentType);
    }

    protected PaymentResponseItem buildBasicResponse(Map<String, Object> paymentResult, PaymentResponseItem baseResponseItem, PaymentContext paymentContext) {
    	
    	Payment payment = (Payment)paymentResult.get(PayPalService.RESULT_PAYMENT);
    	boolean isTransactionSuccess = payment.getState().equals(PayPalService.PAYMENT_STATE_APPROVED);
    	
    	Transaction transaction = payment.getTransactions().get(0);
    	Amount amount = transaction.getAmount();
    	List<RelatedResources> relatedResources = transaction.getRelatedResources();
//    	RelatedResources relatedResource = relatedResources.get(0);
    	baseResponseItem.setTransactionTimestamp(SystemTime.asDate());
        baseResponseItem.setReferenceNumber(payment.getId());
        
        
        baseResponseItem.setTransactionId(payment.getId());
        
        if (isTransactionSuccess) {
        	baseResponseItem.setTransactionAmount(new Money(amount.getTotal(), paymentContext.getPaymentInfo().getOrder().getCurrency().getCurrencyCode()));
        } else {
        	baseResponseItem.getAdditionalFields().put(PayPalService.PAYMENT_STATE, payment.getState());
        	baseResponseItem.setTransactionAmount(new Money(0));
        }

        baseResponseItem.setTransactionSuccess(isTransactionSuccess);
        baseResponseItem.setAuthorizationCode((String)paymentResult.get(PayPalService.RESULT_ACCESS_TOKEN));
        
    	baseResponseItem.setMiddlewareResponseCode(payment.getState());
    	baseResponseItem.setMiddlewareResponseText(payment.getState());
    
        CreditCard creditCard = (CreditCard)paymentResult.get(PayPalService.RESULT_CREDIT_CARD_INFO);
        Map<String, String> additionalFields = new HashMap<String, String>();
        additionalFields.put(PaymentInfoAdditionalFieldType.NAME_ON_CARD.getType(), creditCard.getFirstName()+" "+creditCard.getLastName());
        additionalFields.put(PaymentInfoAdditionalFieldType.CARD_TYPE.getType(), creditCard.getType());
        additionalFields.put(PaymentInfoAdditionalFieldType.EXP_MONTH.getType(), String.valueOf(creditCard.getExpireMonth()));
        additionalFields.put(PaymentInfoAdditionalFieldType.EXP_YEAR.getType(), String.valueOf(creditCard.getExpireYear()));
        additionalFields.put(PaymentInfoAdditionalFieldType.LAST_FOUR.getType(), StringUtils.right(creditCard.getNumber(), 4));
        
        findPaymentInfoFromContext(paymentContext).setAdditionalFields(additionalFields);
        
        return baseResponseItem;
    }
    
//    protected PaymentResponseItem buildBasicDPMResponse(PaymentContext paymentContext, PaymentResponseItem responseItem) {
//        Result result = authorizeNetPaymentService.createResult(paymentContext.getPaymentInfo().getRequestParameterMap());
//
//        if (LOG.isDebugEnabled()){
//            LOG.debug("Amount               : " + result.getResponseMap().get(ResponseField.AMOUNT.getFieldName()));
//            LOG.debug("Response Code        : " + result.getResponseCode());
//            LOG.debug("Response Reason Code : " + result.getReasonResponseCode().getResponseReasonCode());
//            LOG.debug("Response Reason Text : " + result.getResponseMap().get(ResponseField.RESPONSE_REASON_TEXT.getFieldName()));
//            LOG.debug("Transaction ID       : " + result.getResponseMap().get(ResponseField.TRANSACTION_ID.getFieldName()));
//        }
//
//        setBillingInfo(paymentContext, result);
//        setShippingInfo(paymentContext, result);
//        setPaymentInfoAdditionalFields(paymentContext, result);
//
//        responseItem.setTransactionSuccess(isValidTransaction(result));
//        responseItem.setTransactionTimestamp(SystemTime.asDate());
//        responseItem.setProcessorResponseCode(result.getResponseCode().getCode() + "");
//        responseItem.setProcessorResponseText(result.getResponseMap().get(ResponseField.RESPONSE_REASON_TEXT.getFieldName()));
//        setPaymentResponseAdditionalFields(paymentContext, responseItem, result);
//
//        if (isValidTransaction(result)) {
//            responseItem.setTransactionAmount(new Money(result.getResponseMap().get(ResponseField.AMOUNT.getFieldName()), paymentContext.getPaymentInfo().getOrder().getCurrency().getCurrencyCode()));
//        } else {
//            responseItem.setTransactionAmount(new Money(0));
//        }
//
//        saveAnonymousCustomerInfo(paymentContext, responseItem, result);
//
//        return responseItem;
//    }
 
    protected Map<String, String> validateCreditCard(PaymentContext paymentContext){
        CreditCardPaymentInfo ccInfo = (CreditCardPaymentInfo) paymentContext.getReferencedPaymentInfo();
        if ((ccInfo == null) || (ccInfo.getPan() == null)) {
            return null;
        }
        String nameOnCard = ccInfo.getNameOnCard();
        String ccNumber = ccInfo.getPan().replaceAll("[\\s-]+", "");
        Integer expMonth = ccInfo.getExpirationMonth();
        Integer expYear = ccInfo.getExpirationYear();
        String cvv = ccInfo.getCvvCode();

        String cardType = payPalService.validateCardType(ccNumber);
        boolean validCard = !cardType.contains("UNKNOWN");

        DateTime expirationDate = new DateTime(expYear, expMonth, 1, 0, 0);
        boolean validDate = expirationDate.isAfterNow();

        boolean validCVV = !"000".equals(cvv);

        if (validDate && validCard && validCVV){
            Map<String, String> additionalFields = new HashMap<String, String>();
            additionalFields.put(PaymentInfoAdditionalFieldType.NAME_ON_CARD.getType(), nameOnCard);
            additionalFields.put(PaymentInfoAdditionalFieldType.CARD_TYPE.getType(), cardType);
            additionalFields.put(PaymentInfoAdditionalFieldType.EXP_MONTH.getType(), expMonth+"");
            additionalFields.put(PaymentInfoAdditionalFieldType.EXP_YEAR.getType(), expYear+"");
            additionalFields.put(PaymentInfoAdditionalFieldType.LAST_FOUR.getType(), StringUtils.right(ccNumber, 4));
            return additionalFields;
        } else {
            return null;
        }
    }
 
}
